---
title: useTransition
authors: Hypoxia
date: 2025.4.04
---

> 过渡更新，渲染可以被中断的更新

### 基础用法

```tsx
import { useTransition, memo, useState } from "react";

function SlowPost({ index }) {
  let startTime = performance.now();
  while (performance.now() - startTime < 1) {
    // 每个 item 都等待 1 毫秒以模拟极慢的代码。
  }

  return <li className="item">Post #{index + 1}</li>;
}

const PostsTab = memo(function PostsTab() {
  // 打印一次。真正变慢的地方在 SlowPost 内。
  console.log("[ARTIFICIALLY SLOW] Rendering 500 <SlowPost />");

  let items = [];
  for (let i = 0; i < 500; i++) {
    items.push(<SlowPost key={i} index={i} />);
  }
  return <ul className="items">{items}</ul>;
});

export default function App() {
  const [tab, setTab] = useState("1");
  const [isPending, startTransition] = useTransition();

  function onClick(value: string) {
    // 过渡更新
    startTransition(() => {
      setTab(value);
    });
  }

  return (
    <>
      <button onClick={() => onClick("1")}>tab1</button>
      <button onClick={() => onClick("2")}>tab2</button>
      <button onClick={() => onClick("3")}>tab3</button>
      {tab === "1" && <div>tab1</div>}
      {tab === "2" && <PostsTab />}
      {tab === "3" && <div>tab3</div>}
    </>
  );
}
```

1. `[<isPending>, <startTransition>]` useTransition 返回两个参数
   - `isPending`：布尔值，表示是否处于过渡状态
   - `startTransition`：函数，接收一个回调函数作为参数，表示过渡更新的开始
2. `startTransition` 将状态更新包裹，表示该更新是一个过渡更新，它渲染可以被后来的更新中断

### 配合异步

> `useTransition` 可以配合异步使用，以减少渲染频率

```tsx
import { useTransition, useState } from "react";

async function updateQuantity(newQuantity) {
  return new Promise((resolve, reject) => {
    // Simulate a slow network request.
    setTimeout(() => {
      resolve(newQuantity);
    }, 2000);
  });
}

export default function App() {
  const [count, setCount] = useState(1);
  const [isPending, startTransition] = useTransition();

  function handleChange(event) {
    const newQuantity = event.target.value;

    // 过渡更新
    startTransition(async () => {
      const quantity = await updateQuantity(newQuantity);

      startTransition(() => {
        setCount(quantity);
      });
    });
  }

  return (
    <>
      <input type="number" onChange={handleChange} defaultValue={1} min={1} />
      <span>{count * 900}</span>
    </>
  );
}
```

1. `startTransition` 可以包裹异步函数，表示该异步函数是一个过渡更新
2. `startTransition` 可以嵌套使用，可以在异步函数中嵌套状态更新
3. 在所有过渡更新完成后（异步过渡更新需要等到异步完成），才会执行渲染